#include "adc.h"

#define ADC_CH_REMAP                (0u)

/* ADC clock selection definition. */
#define ADC_CLK_PCLK                (1u)
#define ADC_CLK_MPLLQ               (2u)
#define ADC_CLK_UPLLR               (3u)

/* Select MPLLQ as ADC clock. */
#define ADC_CLK                     (ADC_CLK_UPLLR)

/* ADC1 channel definition for this example. */
#define ADC1_SA_NORMAL_CHANNEL      (ADC1_CH9)
#define ADC1_SA_CHANNEL             (ADC1_SA_NORMAL_CHANNEL)
#define ADC1_SA_CHANNEL_COUNT       (1u)
#define ADC1_PORT                   (PortB)
#define ADC1_PIN                    (Pin01)
#define ADC1_CHANNEL                (ADC1_SA_CHANNEL)

#define ADC1_SA_CHANNEL_SAMPLE_TIME 0x30

/*** DMA definition for ADC1. ***/
#define ADC1_SA_DMA_UNIT            (M4_DMA1)
#define ADC1_SA_DMA_PWC             (PWC_FCG0_PERIPH_DMA1) 
#define ADC1_SA_DMA_CH              (DmaCh3)
#define ADC1_SA_DMA_TRGSRC          (EVT_ADC1_EOCA)

/*******M1引脚堵转保护********/
#define ADC1_M1_CHANNEL				(ADC1_CH2)
#define ADC1_M1_PORT                (PortA)
#define ADC1_M1_PIN                 (Pin02)
/*******M2引脚堵转保护********/
#define ADC1_M2_CHANNEL				(ADC1_CH3)
#define ADC1_M2_PORT                (PortA)
#define ADC1_M2_PIN                 (Pin03)
/*******M3引脚堵转保护********/
#define ADC1_M3_CHANNEL				(ADC1_CH4)
#define ADC1_M3_PORT                (PortA)
#define ADC1_M3_PIN                 (Pin04)
/*******M4引脚堵转保护********/
#define ADC1_M4_CHANNEL				(ADC1_CH5)
#define ADC1_M4_PORT                (PortA)
#define ADC1_M4_PIN                 (Pin05)


static void AdcClockConfig(void);
static void AdcInitConfig(void);
static void AdcChannelConfig(void);
static void AdcTriggerConfig(void);
static void AdcDmaConfig(void);

static uint16_t m_au16Adc1Value[ADC1_CH_COUNT];

void adcInit(void)
{
    AdcClockConfig();	//ADC clock
    AdcInitConfig();	//adc配置
    AdcChannelConfig();	//引脚和ADC通道选择
      AdcTriggerConfig();	//触发
     AdcDmaConfig();		
}

/**
 *******************************************************************************
 ** \brief  ADC clock configuration.
 **
 ** \note   1) ADCLK max frequency is 60MHz.
 **         2) If PCLK2 and PCLK4 are selected as the ADC clock,
 **            the following conditions must be met:
 **            a. ADCLK(PCLK2) max 60MHz;
 **            b. PCLK4 : ADCLK = 1:1, 2:1, 4:1, 8:1, 1:2, 1:4
 **
 ******************************************************************************/
static void AdcClockConfig(void)
{		
#if (ADC_CLK == ADC_CLK_PCLK)
    stc_clk_sysclk_cfg_t stcSysclkCfg;		
																
    /* Set bus clock division, depends on the system clock frequency. */
    stcSysclkCfg.enHclkDiv = ClkSysclkDiv1;  // 200MHz
    stcSysclkCfg.enExclkDiv = ClkSysclkDiv2; // 100MHz
    stcSysclkCfg.enPclk0Div = ClkSysclkDiv1; // 200MHz
    stcSysclkCfg.enPclk1Div = ClkSysclkDiv2; // 100MHz
    stcSysclkCfg.enPclk2Div = ClkSysclkDiv4; // 50MHz
    stcSysclkCfg.enPclk3Div = ClkSysclkDiv4; // 50MHz
    stcSysclkCfg.enPclk4Div = ClkSysclkDiv1; // 100MHz.
    CLK_SysClkConfig(&stcSysclkCfg);
    CLK_SetPeriClkSource(ClkPeriSrcPclk);	
											
#elif (ADC_CLK == ADC_CLK_MPLLQ)			
    stc_clk_xtal_cfg_t stcXtalCfg;
    stc_clk_mpll_cfg_t stcMpllCfg;

    if (CLKSysSrcMPLL == CLK_GetSysClkSource())
    {
        /*
         * Configure MPLLQ(same as MPLLP and MPLLR) when you
         * configure MPLL as the system clock.
         */		
    }			
    else		
    {			
        /* Use XTAL as MPLL source. */
        stcXtalCfg.enFastStartup = Enable; 
        stcXtalCfg.enMode = ClkXtalModeOsc;
        stcXtalCfg.enDrv = ClkXtalLowDrv;
        CLK_XtalConfig(&stcXtalCfg);	
        CLK_XtalCmd(Enable);			
										
        /* Set MPLL out 240MHz. */		
        stcMpllCfg.pllmDiv = 2u;//1	
        /* mpll = 8M / pllmDiv * plln */
        stcMpllCfg.plln = 60u;//30
        stcMpllCfg.PllpDiv = 16u;
        stcMpllCfg.PllqDiv = 16u;
        stcMpllCfg.PllrDiv = 16u;
        CLK_SetPllSource(ClkPllSrcXTAL);
        CLK_MpllConfig(&stcMpllCfg);
        CLK_MpllCmd(Enable);
    }
    CLK_SetPeriClkSource(ClkPeriSrcMpllp);

#elif (ADC_CLK == ADC_CLK_UPLLR)
    stc_clk_xtal_cfg_t stcXtalCfg;
    stc_clk_upll_cfg_t stcUpllCfg;

    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcUpllCfg);

    /* Use XTAL as UPLL source. */
    stcXtalCfg.enFastStartup = Enable;
    stcXtalCfg.enMode = ClkXtalModeOsc;
    stcXtalCfg.enDrv = ClkXtalLowDrv;
    CLK_XtalConfig(&stcXtalCfg);
    CLK_XtalCmd(Enable);

    /* Set UPLL out 240MHz. */
    stcUpllCfg.pllmDiv = 2u;
    /* upll = 8M(XTAL) / pllmDiv * plln */
    stcUpllCfg.plln = 60u;
    stcUpllCfg.PllpDiv = 16u;
    stcUpllCfg.PllqDiv = 16u;
    stcUpllCfg.PllrDiv = 16u;
    CLK_SetPllSource(ClkPllSrcXTAL);
    CLK_UpllConfig(&stcUpllCfg);
    CLK_UpllCmd(Enable);
    CLK_SetPeriClkSource(ClkPeriSrcUpllr);
#endif
}

/**
 *******************************************************************************
 ** \brief  ADC initial configuration.		 
 **						 			 	
 ******************************************************************************/
static void AdcInitConfig(void)		
{									
    stc_adc_init_t stcAdcInit; 		
									
    MEM_ZERO_STRUCT(stcAdcInit);	
									
    stcAdcInit.enResolution = AdcResolution_12Bit;//分辨率选择 12位分辨率
    stcAdcInit.enDataAlign = AdcDataAlign_Right;//数据格式 数据格式右对齐
    stcAdcInit.enAutoClear = AdcClren_Disable;//数据寄存器自动清除  自动清除 
    stcAdcInit.enScanMode = AdcMode_SAOnceSBOnce;//扫描模式选择 双序列单次扫描模式
    stcAdcInit.enRschsel = AdcRschsel_Restart;//选择序列 A 被打断后启动方式。
    /* 1. Enable ADC1. */					
    PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Enable);
    /* 2. Initialize ADC1. */				
    ADC_Init(M4_ADC1, &stcAdcInit);			
											
    /* 1. Enable ADC2. */								
    PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC2, Enable);
    /* 2. Initialize ADC2. */
    ADC_Init(M4_ADC2, &stcAdcInit);
}							
/**
 *******************************************************************************
 ** \brief  ADC channel configuration.
 **
 ******************************************************************************/
static void AdcChannelConfig(void)
{
    stc_adc_ch_cfg_t stcChCfg;
    uint8_t au8Adc1SaSampTime = ADC1_SA_CHANNEL_SAMPLE_TIME;

    MEM_ZERO_STRUCT(stcChCfg);
    /*********** 电池引脚配置 ****************/
    /* 1. Set the ADC pin to analog mode. */
    stc_port_init_t stcPortInit; 
    MEM_ZERO_STRUCT(stcPortInit);
    stcPortInit.enPinMode = Pin_Mode_Ana;
    stcPortInit.enPullUp = Disable;
    PORT_Init(ADC1_PORT, ADC1_PIN, &stcPortInit);
	
    stcChCfg.u32Channel = ADC1_SA_CHANNEL;
    stcChCfg.u8Sequence = ADC_SEQ_A;
    stcChCfg.pu8SampTime = &au8Adc1SaSampTime;//抽样时间
	
    /* 2. Add ADC channel. */
    ADC_AddAdcChannel(M4_ADC1, &stcChCfg);
	
	/************M1引脚配置************/
    uint8_t au8Adc1M1Time = ADC1_SA_CHANNEL_SAMPLE_TIME;
    MEM_ZERO_STRUCT(stcChCfg);
	
    stc_port_init_t stcPortInim1;
    MEM_ZERO_STRUCT(stcPortInim1);
    stcPortInim1.enPinMode = Pin_Mode_Ana;
    stcPortInim1.enPullUp = Disable;
    PORT_Init(ADC1_M1_PORT, ADC1_M1_PIN, &stcPortInim1);

    stcChCfg.u32Channel = ADC1_M1_CHANNEL;
    stcChCfg.u8Sequence =  ADC_SEQ_A;
    stcChCfg.pu8SampTime = &au8Adc1M1Time;//抽样时间
    /* 2. Add ADC channel. */
    ADC_AddAdcChannel(M4_ADC1, &stcChCfg);
	
	/************M2引脚配置************/
    uint8_t au8Adc1M2Time = ADC1_SA_CHANNEL_SAMPLE_TIME;
    MEM_ZERO_STRUCT(stcChCfg);
	
    stc_port_init_t stcPortInim2;
    MEM_ZERO_STRUCT(stcPortInim2);
    stcPortInim2.enPinMode = Pin_Mode_Ana;
    stcPortInim2.enPullUp = Disable;
    PORT_Init(ADC1_M2_PORT, ADC1_M2_PIN, &stcPortInim2);

    stcChCfg.u32Channel = ADC1_M2_CHANNEL;
    stcChCfg.u8Sequence =  ADC_SEQ_A;
    stcChCfg.pu8SampTime = &au8Adc1M2Time;//抽样时间
    /* 2. Add ADC channel. */
    ADC_AddAdcChannel(M4_ADC1, &stcChCfg);
	/************ end *************/
	/************M3引脚配置************/
    uint8_t au8Adc1M3Time = ADC1_SA_CHANNEL_SAMPLE_TIME;
    MEM_ZERO_STRUCT(stcChCfg);
	
    stc_port_init_t stcPortInim3;
    MEM_ZERO_STRUCT(stcPortInim3);
    stcPortInim3.enPinMode = Pin_Mode_Ana;
    stcPortInim3.enPullUp = Disable;
    PORT_Init(ADC1_M3_PORT, ADC1_M3_PIN, &stcPortInim3);

    stcChCfg.u32Channel = ADC1_M3_CHANNEL;
    stcChCfg.u8Sequence =  ADC_SEQ_A;
    stcChCfg.pu8SampTime = &au8Adc1M3Time;//抽样时间
    /* 2. Add ADC channel. */
    ADC_AddAdcChannel(M4_ADC1, &stcChCfg);
	/************ end *************/
	/************M4引脚配置************/
    uint8_t au8Adc1M4Time = ADC1_SA_CHANNEL_SAMPLE_TIME;
    MEM_ZERO_STRUCT(stcChCfg);
	
    stc_port_init_t stcPortInim4;
    MEM_ZERO_STRUCT(stcPortInim4);
    stcPortInim4.enPinMode = Pin_Mode_Ana;
    stcPortInim4.enPullUp = Disable;
    PORT_Init(ADC1_M4_PORT, ADC1_M4_PIN, &stcPortInim4);

    stcChCfg.u32Channel = ADC1_M4_CHANNEL;
    stcChCfg.u8Sequence =  ADC_SEQ_A;
    stcChCfg.pu8SampTime = &au8Adc1M4Time;//抽样时间
    /* 2. Add ADC channel. */
    ADC_AddAdcChannel(M4_ADC1, &stcChCfg);
	/************ end *************/
}

/**
 *******************************************************************************
 ** \brief  ADC trigger source configuration.
 **
 ******************************************************************************/
static void AdcTriggerConfig(void)
{
    stc_adc_trg_cfg_t stcTrgCfg;

    MEM_ZERO_STRUCT(stcTrgCfg);

    /*
     * If select an event(@ref en_event_src_t) to trigger ADC,
     * AOS must be enabled first.
     */
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);

    /* ADC1 sequence A will be started by software. */
    ADC_TriggerSrcCmd(M4_ADC1, ADC_SEQ_A, Disable);
}

/**
 *******************************************************************************
 ** \brief  DMA configuration for ADC1 and ADC2.
 **
 ******************************************************************************/
static void AdcDmaConfig(void)
{
    stc_dma_config_t stcDmaCfg;

    MEM_ZERO_STRUCT(stcDmaCfg);

    stcDmaCfg.u16BlockSize = ADC1_CH_COUNT;
    stcDmaCfg.u16TransferCnt = 0u;
    stcDmaCfg.u32SrcAddr = (uint32_t)(&M4_ADC1->DR0);
    stcDmaCfg.u32DesAddr = (uint32_t)(m_au16Adc1Value);
    stcDmaCfg.u16DesRptSize = ADC1_CH_COUNT;
    stcDmaCfg.u16SrcRptSize = ADC1_CH_COUNT;
    stcDmaCfg.u32DmaLlp = 0u;
    stcDmaCfg.stcSrcNseqCfg.u16Cnt = 0u;
    stcDmaCfg.stcSrcNseqCfg.u32Offset = 0u;
    stcDmaCfg.stcDesNseqCfg.u16Cnt = 0u;
    stcDmaCfg.stcDesNseqCfg.u32Offset = 0u;
    stcDmaCfg.stcDmaChCfg.enSrcInc = AddressIncrease;
    stcDmaCfg.stcDmaChCfg.enDesInc = AddressIncrease;
    stcDmaCfg.stcDmaChCfg.enSrcRptEn = Enable;
    stcDmaCfg.stcDmaChCfg.enDesRptEn = Enable;
    stcDmaCfg.stcDmaChCfg.enSrcNseqEn = Disable;
    stcDmaCfg.stcDmaChCfg.enDesNseqEn = Disable;
    stcDmaCfg.stcDmaChCfg.enTrnWidth = Dma16Bit;
    stcDmaCfg.stcDmaChCfg.enLlpEn = Disable;
    stcDmaCfg.stcDmaChCfg.enIntEn = Disable;
	
    PWC_Fcg0PeriphClockCmd(ADC1_SA_DMA_PWC, Enable);
    DMA_InitChannel(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, &stcDmaCfg);
    DMA_Cmd(ADC1_SA_DMA_UNIT, Enable);
    DMA_ChannelCmd(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, Enable);
    DMA_ClearIrqFlag(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, TrnCpltIrq);
    /* AOS must be enabled to use DMA */
    /* AOS enabled at first. */
    /* If you have enabled AOS before, then the following statement is not needed. */
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable);
    DMA_SetTriggerSrc(ADC1_SA_DMA_UNIT, ADC1_SA_DMA_CH, ADC1_SA_DMA_TRGSRC);
}	

void getChannelValue(uint8_t ch, uint16_t *value)
{
    if (ch < ADC1_CH_COUNT)
    {
        *value = m_au16Adc1Value[ch];
    }
}
